

//     Copyright (c) Narin Persad. All rights reserved.The MIT License (MIT)

// Copyright (c) 2014 Narin Persad

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. 
//-----------------------------------------------------------------------


using MvcSimpleQuery.Events;
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Telerik.Web.Mvc.UI;
using MvcSimpleQuery.Html;
using MvcSimpleQuery.HtmlHelpers;
using MvcSimpleQuery.QueryTree;
using System.Linq;
using System.Web.Mvc.Html;
using System.Web;

namespace MvcSimpleQuery.Html
{
    public class HtmlSimpleQueryOptions<C> : IHtmlSimpleQueryOptions where C : Condition
    {




        SimpleQuery SimpleQuery { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="isIndented"></param>
        /// <param name="isFirst"></param>
        public HtmlSimpleQueryOptions(bool isIndented, bool isFirst, HtmlHelper<C> helper)
            : this(helper)
        {

            SimpleQuery.isIndented = isIndented;
            SimpleQuery.IsFirst = isFirst;
            this.helper = helper;
        }
        /// <summary>
        /// 
        /// </summary>
        public HtmlSimpleQueryOptions(HtmlHelper htmlHelper)
        {
            SimpleQuery = new SimpleQuery();

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IHtmlSimpleQueryOptions Named(string name)
        {
            this.SimpleQuery.Name = name;
            return this;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fieldBuilder"></param>
        /// <returns></returns>
        public IHtmlSimpleQueryOptions Fields<T>(Action<FieldBuilder<T>> fieldBuilder) where T : class
        {
            var fb = new FieldBuilder<T>();

            fieldBuilder(fb);
            SimpleQuery.setFields<T>((List<Field>)fb);
            return this;
        }

        public string ToHtmlString()
        {
            var queryTree = new HtmlElement("ol").AddClass("QueryTree").Attribute("id", SimpleQuery.Name)
                .AddChild<HtmlElement>(() =>
                {
                    return new HtmlElement("li").AddClass("folderHeader")
                        .AddChild<HtmlElement>(() =>
                        {
                            return new HtmlElement("label").Attribute("for", "folder1")
                            .AddChild<HtmlElement>(() =>
                            {
                                return new HtmlElement("i").AddClass("glyphicon", "glyphicon-folder-open");
                            });
                        })
                        .AddChild<HtmlElement>(() =>
                        {
                            return new HtmlElement("input").Attribute("id", "folder1").Attribute("type", "checkbox").Attribute("disabled", "").Attribute("checked", "");
                        })
                        .AddChild<HtmlElement>(() =>
                        {
                            return new HtmlElement("ol").Attribute("id", "RootClause")
                                .AddChild<HtmlElement>(() =>
                                {
                                    return (HtmlElement)((SimpleQuery.isIndented) ? IndentedControl : QueryControl);
                                });
                        });
                });

            var script = genScripts();

            var SimpleQueryDiv = new HtmlElement("div").Attribute("id", "QueryWindow");

            SimpleQueryDiv.Children.Add(queryTree);
            SimpleQueryDiv.Children.Add(buildButton);
            SimpleQueryDiv.Children.Add(clearButton);
            SimpleQueryDiv.Children.Add(script);



            return SimpleQueryDiv.ToString().Replace("&quot;", "\"");
        }

        private HtmlElement genScripts()
        {
            var buildEvent = " new CustomEvent("
           + @" ""buildQuery"", {"
           + @"detail: {"
                // + @"	conditions: $(""ol.QueryTree"").getSimpleQuery().buildQuery()"
           + @"	conditions: _cons"
           + @"}"
           + ",bubbles:true"
           + ",cancelable:true"
           + "})";

            var _ReadAction = ReadAction != "" || ReadAction != null ?
              "    $.ajax({" +
               @"          type: ""POST"","
             + @"          url: "" " + ReadAction + @" "","
             + @"          contentType: ""application/json; charset=utf-8"","
             + @"          dataType: ""Json"","
             + @"          data: JSON.stringify(_cons),"
             + @"          success: function (result) {"
             + @"              if(typeof(SQReadCallBack) == typeof(Function)){"
             + @"               SQReadCallBack(result);"
             + @"               }"
             + @"         }"
             + @"      });"
             : "";
            var buildScript = @"$(""#btnBuildQuery"").first().on(""buildQuery""," + SimpleQuery.Events.Build + ");"
                + @" $(""#btnBuildQuery"").on(""click"", function () {"
                + @"var _cons=$(""ol.QueryTree"").getSimpleQuery().buildQuery();"
                + _ReadAction
                + @"this.dispatchEvent(" + buildEvent + ");});";

            var clearScript = @"$(""#btnClear"").first().on(""clearQuery""," + SimpleQuery.Events.Clear + ");"
                + @" $(""#btnClear"").on(""click"", function () {$(""ol.QueryTree"").getSimpleQuery().clearQuery(); this.dispatchEvent(new Event(""clearQuery""))});";

            var autoDrop = @"$("".autodrop"").autodrop();";


            var script = new HtmlElement("script").Attribute("type", "text/javascript")
                .Text(@"$(""ol.QueryTree"").SimpleQuery();"
                + buildScript
                + clearScript
                + (autodropdown ? autoDrop : "")
                );

            return script;
        }
        /// <summary>
        /// 
        /// </summary>
        IHtmlNode buildButton
        {
            get
            {
                var buildButton = new HtmlElement("button")
                    .Attribute("id", "btnBuildQuery")
                    .Attribute("data-loading-text", "Loading...")
                    .Attribute("style", @"float:right")
                    .AddClass("btn", "btn-mini", "btn-primary")
                    .Text("Execute");
                return buildButton;
            }

        }

        /// <summary>
        /// 
        /// </summary>
        IHtmlNode clearButton
        {
            get
            {

                var clearButton = new HtmlElement("button")
                    .Attribute("id", "btnClear")
                    .Attribute("data-loading-text", "Loading...")
                    .Attribute("style", @"float:right;margin-right:10px")
                    .AddClass("btn", "btn-mini", "btn-primary")
                    .Text("Clear");
                return clearButton;
            }
        }

        /// <summary>
        /// One row in the query tree
        /// </summary>
        IHtmlNode QueryControl
        {
            get
            {

                var field_op = autodropdown ? new HtmlElement("div").AddClass("row")//.AddClass("queryControl")
                                     .AddChild<HtmlElement>(() =>
                                     {
                                         return new HtmlElement("div").AddClass("col-md-3")
                                         .AddChild<HtmlElement>(() =>
                                         {
                                             return (HtmlElement)FieldDropDown;
                                         });
                                     })
                                     .AddChild<HtmlElement>(() =>
                                     {
                                         return new HtmlElement("div").AddClass("col-md-3")
                                        .AddChild<HtmlElement>(() =>
                                        {
                                            return (HtmlElement)FieldOperation;
                                        });
                                     })
                :
                new HtmlElement("div").AddClass("row")//.AddClass("queryControl")
                                     .AddChild<HtmlElement>(() =>
                                     {
                                         return new HtmlElement("div").AddClass("col-md-6")
                                             .AddChild<HtmlElement>(() =>
                                             {
                                                 return new HtmlElement("div").AddClass("btn-group").AddClass("btn-group-justified")
                                                 .AddChild<HtmlElement>(() =>
                                                 {
                                                     return (HtmlElement)FieldDropDown;
                                                 }).AddChild<HtmlElement>(() =>
                                                 {
                                                     return (HtmlElement)FieldOperation;
                                                 });
                                             });
                                     });

                var file = new HtmlElement("li").AddClass("file")
                               .AddChild<HtmlElement>(() =>
                               {
                                   return field_op
                                          .AddChild<HtmlElement>(() =>
                                          {
                                              return new HtmlElement("div").AddClass("col-md-3")
                                                  .AddChild<HtmlElement>(() =>
                                                  {
                                                      return new HtmlElement("input").Attribute("type", "text").Attribute("data-name", "condition.Value").Attribute("placeholder", "Value").AddClass("form-control", "Value", "Query");
                                                  });
                                          })
                                          .AddChild<HtmlElement>(() =>
                                          {
                                              return new HtmlElement("div").AddClass("col-md-3")
                                                  .AddChild<HtmlElement>(() =>
                                                  {
                                                      return new HtmlElement("div").AddClass("btn-group", "btn-group-justified")
                                                           .AddChild<HtmlElement>(() =>
                                                           {
                                                               return (HtmlElement)Conjunction;
                                                           })
                                                           .AddChild<HtmlElement>(() =>
                                                           {
                                                               return (HtmlElement)Plus;
                                                           }).AddChild<HtmlElement>(() =>
                                                           {
                                                               return (HtmlElement)Minus;
                                                           });
                                                  });
                                          });
                               });
                return file;
            }
        }
        /// <summary>
        /// If the row is indented query control is surrounded by appropriate controls
        /// </summary>
        IHtmlNode IndentedControl
        {
            get
            {
                return new HtmlElement("li").AddClass("folderHeader")
                       .AddChild<HtmlElement>(() =>
                       {
                           return new HtmlElement("label").Attribute("for", "bleh")
                                 .AddChild<HtmlElement>(() =>
                                 {
                                     return new HtmlElement("i").AddClass(() => { return this.SimpleQuery.IsFirst ? new string[] { "glyphicon", "glyphicon-folder-open" } : new string[] { "glyphicon", "glyphicon-folder-close" }; })
                                           .Text("Condition");
                                 })
                                  .AddChild<HtmlElement>(() =>
                                  {
                                      return new HtmlElement("input").Attribute("type", "checkbox");
                                  })
                                  .AddChild<HtmlElement>(() =>
                                  {
                                      return new HtmlElement("ol")
                                      .AddChild<HtmlElement>(() =>
                                      {
                                          /***Query Control***/
                                          return (HtmlElement)QueryControl;
                                      });
                                  }).AddChild<HtmlElement>(() =>
                                  {
                                      return new HtmlElement("input").Attribute("type", "hidden").Attribute("data-name", "condition.isSubCondtion").Attribute("value", "true").AddClass("Query")
                                    .AddChild<HtmlElement>(() =>
                                    {
                                        return new HtmlElement("div").AddClass("btn-group", "subConnector").Attribute("data-toggle", "buttons")
                                           .AddChild<HtmlElement>(() =>
                                           {
                                               return new HtmlElement("label").AddClass("btn", "btn-primary","active", "btn-xs").Attribute("data-toggle", "tooltip").Attribute("data-placement", "left").Attribute("title", "The conjunction that will be used to connect the adjacent clause.")
                                                   .AddChild<HtmlElement>(() =>
                                                   {
                                                       return new HtmlElement("input").Attribute("type", "radio").Attribute("data-name", "condition.Conjunction").AddClass("Query").Attribute("checked", "checked").Attribute("value", "AND").Text("AND");
                                                   });
                                           })
                                           .AddChild<HtmlElement>(() =>
                                           {
                                               return new HtmlElement("label").AddClass("btn", "btn-primary", "btn-xs")
                                                 .AddChild<HtmlElement>(() =>
                                                 {
                                                     return new HtmlElement("input").Attribute("type", "radio").Attribute("data-name", "condition.Conjunction").AddClass("Query").Attribute("value", "OR").Text("OR");
                                                 });
                                           });
                                    });
                                  });
                       });
            }
        }
        /// <summary>
        /// The fields that were added through the FieldBuilder action of the HtmlSimpleQuery object
        /// </summary>
        IHtmlNode FieldDropDown
        {
            get
            {

                return autodropdown ?
                    helper.SegmentedButton<C, string>(x => x.Field, SimpleQuery.Fields.Select(x => new SelectListItem { Text = x.Name, Value = x.Name }), null).AddClass("Field") :
                    // helper.BootstrapSplitButtonDropDown<C, string>(x => x.Field, SimpleQuery.Fields.Select(x => new SelectListItem { Text = x.Name, Value = x.Name }), null,true);
                 helper.ButtonDropDown<C, string>(x => x.Field,
                 SimpleQuery.Fields.Select(x => new SelectListItem { Text = x.Name, Value = x.Name }),
                 (button) =>
                 {
                     button
                         .AddChild<HtmlElement>(() =>
                         {
                             return new HtmlElement("span").Attribute("data-bind", "label").Text("Field");
                         })
                         .AddChild2<LiteralNode>(() =>
                         {
                             return new LiteralNode(" ");
                         })
                         .AddChild<HtmlElement>(() =>
                         {
                             return new HtmlElement("span").AddClass("caret");
                         });

                 }).AddClass("Field");
            }
        }
        /// <summary>
        /// The filters that will operate on the field and value
        /// </summary>
        IHtmlNode FieldOperation
        {
            get
            {
                var operations = new string[] { "le", "lte", "gt", "gte", "eq", "neq" }.Select(x => new SelectListItem { Text = x, Value = x });

                return autodropdown ?
                   helper.SegmentedButton<C, string>(x => x.Operation, operations, null).AddClass("Operation") :
                 helper.ButtonDropDown<C, string>(x => x.Operation,
                operations,
                (button) =>
                {
                    button
                        .AddChild<HtmlElement>(() =>
                        {
                            return new HtmlElement("span").Attribute("data-bind", "label").Text("Operation");
                        })
                        .AddChild2<LiteralNode>(() =>
                        {
                            return new LiteralNode(" ");
                        })
                        .AddChild<HtmlElement>(() =>
                        {
                            return new HtmlElement("span").AddClass("caret");
                        });
                }).AddClass("Operation");
            }
        }
        /// <summary>
        /// The conjunction and/or that is used to join (sub)conditions
        /// </summary>
        IHtmlNode Conjunction
        {
            get
            {
                var _CON = helper.ButtonDropDown<C, string>(x => x.Conjunction,
                    new string[] { "AND", "OR" }.Select(x => new SelectListItem { Text = x, Value = x }),
                    (button) =>
                    {
                        button
                         .AddChild<HtmlElement>(() =>
                         {
                             return new HtmlElement("span").Attribute("data-bind", "label")
                                 .AddChild<HtmlElement>(() =>
                                            {
                                                return new HtmlElement("i").AddClass("glyphicon glyphicon-magnet");
                                            });
                         });

                    }).AddClass("Conjunction");
                return _CON;
            }
        }
        /// <summary>
        /// The control to add a new (sub)condition
        /// </summary>
        IHtmlNode Plus
        {
            get
            {
                var _CON = helper.ButtonDropDown<C, string>(x => "",
                    new string[] { "+", "(" }.Select(x => new SelectListItem { Text = x, Value = x }),
                    (button) =>
                    {
                        button.AddChild<HtmlElement>(() =>
                        {
                            return new HtmlElement("span")
                                              .AddChild<HtmlElement>(() =>
                                              {
                                                  return new HtmlElement("i").AddClass("glyphicon glyphicon-plus");
                                              });
                        });
                    }).AddClass("Add");
                return _CON;
            }

        }
        /// <summary>
        /// The control to remove a (sub)condition
        /// </summary>
        IHtmlNode Minus
        {
            get
            {
                return new HtmlElement("div").AddClass("btn-group", "Remove")
                   .AddChild<HtmlElement>(() =>
                   {
                       return new HtmlElement("button").AddClass("btn", "btn-default", "dropdown-toggle").Attribute("data-toggle", "dropdown")
                            .AddChild<HtmlElement>(() =>
                            {
                                return new HtmlElement("i").AddClass("glyphicon glyphicon-minus");
                            });
                   });

            }
        }

        public IHtmlSimpleQueryOptions Events(Action<ISimpleQueryEventBuilder> sevb)
        {
            var eventBuilder = new SimpleQueryEvents();
            sevb(eventBuilder);
            this.SimpleQuery.@Events = eventBuilder;
            return this;
        }



        public HtmlHelper<C> helper { get; set; }


        public IHtmlSimpleQueryOptions AutoDrop(bool autodropdown)
        {
            this.autodropdown = autodropdown;
            return this;
        }

        public bool autodropdown { get; set; }


        public IHtmlSimpleQueryOptions Read(System.Linq.Expressions.Expression<Func<UrlHelper, string>> urlhepher)
        {
            var helper = urlhepher.Compile();
            UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);

            ReadAction = helper(urlHelper);

            return this;
        }

        public string ReadAction { get; set; }
    }
}
